#ifndef _ADXL345_H_
#define _ADXL345_H_

#include <stdint.h>
#include "platform.h"
#include "board_spi.h"

#ifndef GRAVITY
#	define GRAVITY	9.8015f
#endif

#ifndef PI
#	define PI	3.1415926f
#endif

/**
 *  * Defines
 *   */
//Registers.
#define ADXL345_DEVID_REG          ((uint8_t)0x00)
#define ADXL345_THRESH_TAP_REG     ((uint8_t)0x1D)
#define ADXL345_OFSX_REG           ((uint8_t)0x1E)
#define ADXL345_OFSY_REG           ((uint8_t)0x1F)
#define ADXL345_OFSZ_REG           ((uint8_t)0x20)
#define ADXL345_DUR_REG            ((uint8_t)0x21)
#define ADXL345_LATENT_REG         ((uint8_t)0x22)
#define ADXL345_WINDOW_REG         ((uint8_t)0x23)
#define ADXL345_THRESH_ACT_REG     ((uint8_t)0x24)
#define ADXL345_THRESH_INACT_REG   ((uint8_t)0x25)
#define ADXL345_TIME_INACT_REG     ((uint8_t)0x26)
#define ADXL345_ACT_INACT_CTL_REG  ((uint8_t)0x27)
#define ADXL345_THRESH_FF_REG      ((uint8_t)0x28)
#define ADXL345_TIME_FF_REG        ((uint8_t)0x29)
#define ADXL345_TAP_AXES_REG       ((uint8_t)0x2A)
#define ADXL345_ACT_TAP_STATUS_REG ((uint8_t)0x2B)
#define ADXL345_BW_RATE_REG        ((uint8_t)0x2C)
#define ADXL345_POWER_CTL_REG      ((uint8_t)0x2D)
#define ADXL345_INT_ENABLE_REG     ((uint8_t)0x2E)
#define ADXL345_INT_MAP_REG        ((uint8_t)0x2F)
#define ADXL345_INT_SOURCE_REG     ((uint8_t)0x30)
#define ADXL345_DATA_FORMAT_REG    ((uint8_t)0x31)
#define ADXL345_DATAX0_REG         ((uint8_t)0x32)
#define ADXL345_DATAX1_REG         ((uint8_t)0x33)
#define ADXL345_DATAY0_REG         ((uint8_t)0x34)
#define ADXL345_DATAY1_REG         ((uint8_t)0x35)
#define ADXL345_DATAZ0_REG         ((uint8_t)0x36)
#define ADXL345_DATAZ1_REG         ((uint8_t)0x37)
#define ADXL345_FIFO_CTL           ((uint8_t)0x38)
#define ADXL345_FIFO_STATUS        ((uint8_t)0x39)

//Data rate codes.
#define ADXL345_PM_LOWPOWER	((uint8_t)0x10)
#define ADXL345_PM_NORMAL	((uint8_t)0x00)

#define ADXL345_3200HZ      ((uint8_t)0x0F)
#define ADXL345_1600HZ      ((uint8_t)0x0E)
#define ADXL345_800HZ       ((uint8_t)0x0D)
#define ADXL345_400HZ       ((uint8_t)0x0C)
#define ADXL345_200HZ       ((uint8_t)0x0B)
#define ADXL345_100HZ       ((uint8_t)0x0A)
#define ADXL345_50HZ        ((uint8_t)0x09)
#define ADXL345_25HZ        ((uint8_t)0x08)
#define ADXL345_12HZ5       ((uint8_t)0x07)
#define ADXL345_6HZ25       ((uint8_t)0x06)

#define ADXL345_FULL_RES	((uint8_t)0x08)
#define ADXL345_10BIT_RES	((uint8_t)0x00)

#define ADXL345_FS_2G		((uint8_t)0x00)
#define ADXL345_FS_4G		((uint8_t)0x01)
#define ADXL345_FS_8G		((uint8_t)0x02)
#define ADXL345_FS_16G		((uint8_t)0x03)

typedef struct {
    uint8_t Power_Mode;
    uint8_t Output_Data_Rate;
    uint8_t Full_Res;
    uint8_t Full_Scale;                         /* Full scale */
    volatile uint8_t status;
} ADXL345_InitTypeDef;

/* working status enum */
enum {
    ADXL_INIT = 0,
    ADXL_READ_ACC,
    ADXL_SET_FS
};

/* init status enum */
enum {
    ADXL_UNIDENTIFIED = 0,
    ADXL_STANDBY,
    ADXL_SET_RATE,
    ADXL_SET_FORMAT,
    ADXL_CHECK_FS,
    ADXL_ENABLE,
    ADXL_COMPLETE
};

typedef struct {
    SPI_HandleTypeDef* spi;
    ADXL345_InitTypeDef initStructure;
    uint8_t* rx_byte;
    uint8_t init_delay;
    struct imu_raw_data *p_imu;
    void (*rx_handler)(void* pAdxl);
    volatile uint8_t status;
} ADXL345_HandleTypeDef;

void adxl345_nonblocking_process(ADXL345_HandleTypeDef* adxlHandler);

uint8_t adxl345_set_acc_range(uint8_t range);

/* test function */
uint8_t adxl345_read_pid(ADXL345_HandleTypeDef* adxl);

#endif
